import re
import linecache
import os
import time
import datetime
import xlrd
from xlutils.copy import copy
import shutil
import sys
import mmap
import openpyxl
import os
from matplotlib import pyplot as plt
import numpy as np
class COLORTOOL:

    def __init__(self):
        self.starttime = datetime.datetime.now()
        self.new_excel_path = None
        self.excel_path = "Transsion_color_excel.xlsx"
        self.global_sat_list = []
        self.hue_list = []
        self.color_line_num = []
        self.sat_gain1_list = []
        self.sat_gain2_list = []
        self.sat_gain3_list = []
        self.sat_point1_list = []
        self.sat_point2_list = []
        self.sat_gain_by0_list = []
        self.sat_gain_by64_list = []
        self.sat_gain_by128_list = []
        self.sat_gain_by192_list = []
        self.sat_gain_by256_list = []
        self.color_param_list = []
        self.line_status = {}
        self.image_names = []
        self.image_names1 = []
        self.issues = []
        self.threshold = None
        self.hue_max = None
        self.hue_min = None
        self.sat_max = None
        self.sat_min = None


    def setSavepath(self, path):
        self.save_excel_path = path
        self.plot_path = os.path.join(path, 'color_isp6s_jpg/')
        if not os.path.exists(self.plot_path):
            os.makedirs(self.plot_path)
    def setcpppath(self, path):
        self.color_path = path
        linecache.clearcache()
        linecache.checkcache(self.color_path)
    def run_read_color(self):
        start_time = time.time()
        line_num = self.read_file_str_num(self.color_path, 'COLOR_BASE[') + 2
        if line_num == 2:
            print('[Error]', self.color_path + ' color文件不对，请check')
            return
        # print(f"File {self.color_path} last modified: {time.ctime(os.path.getmtime(self.color_path))}")
        # # 强制刷新文件缓存
        # try:
        #     print(f"Refreshing file cache for: {self.color_path}")
        #     with open(self.color_path, 'r', encoding='utf-8') as f:
        #         f.read()
        # except Exception as e:
        #     print('[Error]', f"打开失败 {self.color_path} 不存在，请check")
        #     print('[Error]', e)
        #     return

        try:
            rb1 = xlrd.open_workbook(self.excel_path, formatting_info=True)
            self.wb1 = copy(rb1)
            self.ws1 = self.wb1.get_sheet(0)
        except Exception as e:
            print('[Error]', "excel文件可能不存在，请check")
            print('[Error]', e)
            return 0
        self.color_line_num = [line_num + i * 173 for i in range(60)]  # 使用列表推导式
        for color_line_num_index, line_num in enumerate(self.color_line_num):
            self._data_clear()
            for i in range(20):
                self._extract_color_data(line_num, i)
                if '9999' in self.hue_list:
                    print(f'[Error] 该行中不存在.COLOR_hue_to_hue_{i}=字符串')
                    return
            self.code2excel(2 + 12 * color_line_num_index)
        save_path = os.path.join(self.save_excel_path, 'COLOR.xlsx')
        try:
            self.wb1.save(save_path)
        except Exception as e:
            print('[Error]', "excel文件要关闭并且不能有中文路径")
            print('[Error]', e)
            return 0
        # end_time = time.time()
        # endtime = datetime.datetime.now()
        # current_folder_name = os.path.basename(os.path.dirname(self.color_path))
        # print(f'[Success] [{current_folder_name}] code参数写入excel 成功')
        # print(f'[Success] [{current_folder_name}] color参数打印写入color_jpg文件 成功')
        # print("运行时间: {:.2f}秒".format(end_time - start_time))
        # print(f"ColorCheck Done！运行时间: {endtime - self.starttime}\n")
    def _extract_color_data(self, base_line_num, i):
        offsets = [58, 67, 72, 77, 82, 87, 92, 97, 102, 107, 112, 117]
        self.global_sat_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[0]), ".COLOR_g_saturation="))
        self.hue_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[1] + i // 4), f".COLOR_hue_to_hue_{i}="))
        self.sat_gain1_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[2] + i // 4), f".COLOR_sat_gain1_hue_{i}="))
        self.sat_gain2_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[3] + i // 4), f".COLOR_sat_gain2_hue_{i}="))
        self.sat_gain3_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[4] + i // 4), f".COLOR_sat_gain3_hue_{i}="))
        self.sat_point1_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[5] + i // 4), f".COLOR_sat_point1_hue_{i}="))
        self.sat_point2_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[6] + i // 4), f".COLOR_sat_point2_hue_{i}="))
        self.sat_gain_by0_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[7] + i // 4), f".COLOR_s_gain_y0_hue_{i}="))
        self.sat_gain_by64_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[8] + i // 4), f".COLOR_s_gain_y64_hue_{i}="))
        self.sat_gain_by128_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[9] + i // 4), f".COLOR_s_gain_y128_hue_{i}="))
        self.sat_gain_by192_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[10] + i // 4), f".COLOR_s_gain_y192_hue_{i}="))
        self.sat_gain_by256_list.append(self.digital_in_str(linecache.getline(self.color_path, base_line_num + offsets[11] + i // 4), f".COLOR_s_gain_y256_hue_{i}="))

    def read_file_str_num(self, filename, search_str):
        # 找某一个字符串在这个文件中的行数
        line_num = 0
        try:
            with open(filename, 'r', encoding='utf-8') as f:
                for line_num, line in enumerate(f, 1):  # 使用 enumerate 直接计数行号
                    if line_num > 60 and search_str in line:
                        return line_num
        except Exception as e:
            print('[Error]', f"打开失败 {filename} 不存在，请check")
        return 0

    def digital_in_str(self, whole_str, sub_str):
        if sub_str not in whole_str:
            return '9999'
        try:
            return re.findall(r'(\d+)', whole_str.split(sub_str)[1])[0]
        except IndexError:
            return '9999'



    def _data_clear(self):
        self.global_sat_list.clear()
        self.hue_list.clear()
        self.sat_gain1_list.clear()
        self.sat_gain2_list.clear()
        self.sat_gain3_list.clear()
        self.sat_point1_list.clear()
        self.sat_point2_list.clear()
        self.sat_gain_by0_list.clear()
        self.sat_gain_by64_list.clear()
        self.sat_gain_by128_list.clear()
        self.sat_gain_by192_list.clear()
        self.sat_gain_by256_list.clear()





    def code2excel(self,row_num):  # 从第多少行开始写入，比如3，代表从第三行开始写

        self.ws1.write(row_num, 4, self.global_sat_list[0])
        for j in range(4, 24):
            self.ws1.write(row_num + 1, j, self.hue_list[j - 4])
            self.ws1.write(row_num + 2, j, self.sat_gain1_list[j - 4])
            self.ws1.write(row_num + 3, j, self.sat_gain2_list[j - 4])
            self.ws1.write(row_num + 4, j, self.sat_gain3_list[j - 4])
            self.ws1.write(row_num + 5, j, self.sat_point1_list[j - 4])
            self.ws1.write(row_num + 6, j, self.sat_point2_list[j - 4])
            self.ws1.write(row_num + 7, j, self.sat_gain_by0_list[j - 4])
            self.ws1.write(row_num + 8, j, self.sat_gain_by64_list[j - 4])
            self.ws1.write(row_num + 9, j, self.sat_gain_by128_list[j - 4])
            self.ws1.write(row_num + 10, j, self.sat_gain_by192_list[j - 4])
            self.ws1.write(row_num + 11, j, self.sat_gain_by256_list[j - 4])


        pass

    def get_color_data(self, line_num):
        self._data_clear()
        self.global_sat_list.append(
            self.digital_in_str(linecache.getline(self.color_path, line_num + 58), ".COLOR_g_saturation="))
        for i in range(0, 20):
            self.hue_list.append(self.digital_in_str(linecache.getline(self.color_path, line_num + 67 + i // 4),
                                                     ".COLOR_hue_to_hue_" + str(i) + "="))
            if '9999' in self.hue_list:
                print('[Error]', '该行中不存在' + ".COLOR_hue_to_hue_" + str(i) + "=" + '字符串')
                return False
            self.sat_gain1_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 72 + i // 4),
                                    ".COLOR_sat_gain1_hue_" + str(i) + "="))
            self.sat_gain2_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 77 + i // 4),
                                    ".COLOR_sat_gain2_hue_" + str(i) + "="))
            self.sat_gain3_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 82 + i // 4),
                                    ".COLOR_sat_gain3_hue_" + str(i) + "="))
            self.sat_point1_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 87 + i // 4),
                                    ".COLOR_sat_point1_hue_" + str(i) + "="))
            self.sat_point2_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 92 + i // 4),
                                    ".COLOR_sat_point2_hue_" + str(i) + "="))
            self.sat_gain_by0_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 97 + i // 4),
                                    ".COLOR_s_gain_y0_hue_" + str(i) + "="))
            self.sat_gain_by64_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 102 + i // 4),
                                    ".COLOR_s_gain_y64_hue_" + str(i) + "="))
            self.sat_gain_by128_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 107 + i // 4),
                                    ".COLOR_s_gain_y128_hue_" + str(i) + "="))
            self.sat_gain_by192_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 112 + i // 4),
                                    ".COLOR_s_gain_y192_hue_" + str(i) + "="))
            self.sat_gain_by256_list.append(
                self.digital_in_str(linecache.getline(self.color_path, line_num + 117 + i // 4),
                                    ".COLOR_s_gain_y256_hue_" + str(i) + "="))
        return True

    def color_plot(self, index):
        X_Vaule = range(0, 20)
        plt.subplot(2, 1, 1)

        plt.title(r"$\bf{" + "LV:" + "}$" + str(int(index / 10)) + "\t" + r"$\bf{" + "CT:" + "}$"
                      + str(int(index % 10)) + "\t" + r"$\bf{" + "Global Sat:" + "}$" + str(self.global_sat_list[0]))
        plt.plot(X_Vaule, list(map(int, self.hue_list)), label='hue', color="red", linewidth=1.0, linestyle="-")
        plt.yticks(np.linspace(0, 256, 11))
        plt.xticks(range(0, 21))
        plt.legend()
        plt.ylabel("HUE Value")
        plt.subplot(2, 1, 2)
        plt.plot(X_Vaule, list(map(int, self.sat_gain1_list)), label='sat_gain1', color="blue", linewidth=1.0,
                 linestyle="-")
        plt.plot(X_Vaule, list(map(int, self.sat_gain2_list)), label='sat_gain2', color="green", linewidth=1.0,
                 linestyle="-.")
        plt.plot(X_Vaule, list(map(int, self.sat_gain3_list)), label='sat_gain3', color="yellow", linewidth=1.0,
                 linestyle="--")
        plt.yticks(np.linspace(0, 256, 11))
        plt.xticks(range(0, 21))
        plt.legend()
        plt.xlabel("Index")
        plt.ylabel("SAT Value")

    def save_image(self, index):

        # 显示下拉图片名字
        lv = index // 10  # 整数除法
        ct = index % 10  # 取余
        image_name = os.path.join( 'COLOR_{:02d}{:01d}.png'.format(lv, ct))  # 确保路径拼接正确
        image_name1 = 'COLOR_{}{}.png'.format(lv, ct)
        plt.savefig(self.plot_path + 'COLOR_{}.png'.format(index))
        plt.clf()
        self.image_names.append(image_name)
        self.image_names1.append(image_name1)

    def generate_and_save_image(self):
        line_num = self.read_file_str_num(self.color_path, 'COLOR_BASE[') + 2
        self.color_line_num = [line_num + i * 173 for i in range(60)]  # 使用列表推导式
        for idx, num in enumerate(self.color_line_num):
            if self.get_color_data(num):
                self.color_plot(idx)  # 传递单个整数
                self.save_image(idx)  # 传递列表索引 idx, 确保从 0 到 59
            else:
                print("[Error] Failed to get color data")

    def check_data(self, index):
        if not hasattr(self, 'large_diff_issues'):
            self.large_diff_issues = set()
            self.all_points_128_issues = set()
            self.hue_max_issues = set()
            self.hue_min_issues = set()
            self.sat_max_issues = set()
            self.sat_min_issues = set()

        # 检查每条线的相邻两个点的差值绝对值是否大于阈值
        if self.threshold is not None:
            for name, data in [("HUE", self.hue_list), ("sat_gain1", self.sat_gain1_list),
                               ("sat_gain2", self.sat_gain2_list), ("sat_gain3", self.sat_gain3_list)]:
                for i in range(1, len(data)):
                    if abs(float(data[i]) - float(data[i - 1])) > self.threshold:
                        # self.issues.append(
                        #     f"Image {index}: {name} line has a large difference between points {i - 1} and {i}")
                        self.large_diff_issues.add(index)

        # 检查每条线的所有点是否都等于128
        # for name, data in [("HUE", self.hue_list), ("sat_gain1", self.sat_gain1_list),
        #                    ("sat_gain2", self.sat_gain2_list), ("sat_gain3", self.sat_gain3_list)]:
        #     if all(float(value) == 128 for value in data):
        #         # self.issues.append(f"Image {index}: All points in {name} line are 128")
        #         self.all_points_128_issues.add(index)
        if (all(float(value) == 128 for value in self.hue_list) and
                all(float(value) == 128 for value in self.sat_gain1_list) and
                all(float(value) == 128 for value in self.sat_gain2_list) and
                all(float(value) == 128 for value in self.sat_gain3_list)):
            # self.issues.append(
            #     f"Image {index}: All points in lines are 128")
            self.all_points_128_issues.add(index)
        hue_Max = max(map(float, self.hue_list))
        hue_Min = min(map(float, self.hue_list))

        if self.hue_max is not None and hue_Max > self.hue_max:
            # self.issues.append(
            #     f"Image {index}: HUE line has a value {hue_Max} exceeding the max threshold {self.hue_max}")
            self.hue_max_issues.add(index)

        if self.hue_min is not None and hue_Min < self.hue_min:
            # self.issues.append(
            #     f"Image {index}: HUE line has a value {hue_Min} below the min threshold {self.hue_min}")
            self.hue_min_issues.add(index)

        # 检查 sat_gain1, sat_gain2, sat_gain3 的最大值和最小值
        for name, data in [("sat_gain1", self.sat_gain1_list), ("sat_gain2", self.sat_gain2_list),
                           ("sat_gain3", self.sat_gain3_list)]:
            max_sat = max(map(float, data))
            min_sat = min(map(float, data))

            if self.sat_max is not None and max_sat > self.sat_max:
                # self.issues.append(
                #     f"Image {index}: {name} line has a value {max_sat} exceeding the max threshold {self.sat_max}")
                self.sat_max_issues.add(index)

            if self.sat_min is not None and min_sat < self.sat_min:
                # self.issues.append(
                #     f"Image {index}: {name} line has a value {min_sat} below the min threshold {self.sat_min}")
                self.sat_min_issues.add(index)

    def generate_summary(self):
        summary = []
        if hasattr(self, 'large_diff_issues') and self.large_diff_issues:
            summary.append("参数差值超出阈值的有: ")
            summary.append(", ".join(map(str, sorted(self.large_diff_issues))))

        if hasattr(self, 'all_points_128_issues') and self.all_points_128_issues:
            summary.append("参数未修改的有: ")
            summary.append(", ".join(map(str, sorted(self.all_points_128_issues))))

        # 合并HUE的最大值和最小值检查
        hue_issues = set()
        if hasattr(self, 'hue_max_issues') and self.hue_max_issues:
            hue_issues.update(self.hue_max_issues)
        if hasattr(self, 'hue_min_issues') and self.hue_min_issues:
            hue_issues.update(self.hue_min_issues)
        if hue_issues:
            summary.append("参数HUE不合理的有 ")
            summary.append(", ".join(map(str, sorted(hue_issues))))

        # 合并SAT的最大值和最小值检查
        sat_issues = set()
        if hasattr(self, 'sat_max_issues') and self.sat_max_issues:
            sat_issues.update(self.sat_max_issues)
        if hasattr(self, 'sat_min_issues') and self.sat_min_issues:
            sat_issues.update(self.sat_min_issues)
        if sat_issues:
            summary.append("参数SAT不合理的有: ")
            summary.append(", ".join(map(str, sorted(sat_issues))))
        if summary:
            summary.insert(0, "####################### COLOR Result##########################")
            summary.append("############################################################"+"\n")
        self.issues.append("\n".join(summary))


    def check_data2(self):
        line_num = int(self.read_file_str_num(self.color_path, 'COLOR_BASE[')) + 2
        if line_num == 0:
            print('[Error]', self.color_path + '  color文件不对，请check')
            return
        self.color_line_num = [line_num + i * 173 for i in range(60)]  # 使用列表推导式
        for idx, line_num in enumerate(self.color_line_num):
            self.issues = []  # 初始化 issues 列表
            if not self.get_color_data(line_num):
                continue  # 如果获取数据失败，跳过当前行
            self.check_data(idx)
            # if self.issues:
            #     with open("data_issues.txt", "w") as f:
            #         for issue in self.issues:
            #             f.write(issue + "\n")




